<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据比对原型工具</title>
    <!-- 引入 Tailwind CSS -->
    <script src="/static/tailwindcss.css"></script>
    <script src="/static/xlsx.full.min.js"></script>
    <style>
        /* 自定义滚动条样式 */
        ::-webkit-scrollbar {
            width: 8px;
            height: 8px;
        }
        ::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 10px;
        }
        ::-webkit-scrollbar-thumb {
            background: #888;
            border-radius: 10px;
        }
        ::-webkit-scrollbar-thumb:hover {
            background: #555;
        }

        /* 自定义颜色类 */
        .bg-match { background-color: #d4edda; } /* 匹配数据 - 浅绿色 */
        .bg-left-only { background-color: #f8d7da; } /* 左表独有 - 浅红色 */
        .bg-right-only { background-color: #d1ecf1; } /* 右表独有 - 浅蓝色 */
        .bg-diff-field { background-color: #fff3cd; } /* 字段值不同 - 浅黄色 */
        .bg-header { background-color: #e2e8f0; } /* 表头背景色 */

        /* 拖放字段样式 */
        .field-item {
            display: inline-flex;
            align-items: center;
            padding: 0.3rem 0.6rem; /* Slightly smaller padding */
            background-color: #e0f2fe; /* light blue */
            border: 1px solid #90cdf4; /* blue-300 */
            border-radius: 0.375rem; /* rounded-md */
            font-size: 0.875rem; /* text-sm */
            cursor: grab;
            user-select: none;
            box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
            margin: 0.25rem; /* Add margin for spacing */
        }
        .field-item.dragging {
            opacity: 0.5;
            border-style: dashed;
        }
        .field-item .remove-btn {
            display: flex;
            align-items: center;
            justify-content: center;
            height: 32px;
            width: 32px;
            text-align: center;
            padding: 0;
            margin-left: 0.5rem;
            color: #ef4444;
            cursor: pointer;
            font-weight: bold;
            font-size: 18px;
            border-radius: 8px;
            border: none;
            background: transparent;
            transition: background 0.15s, color 0.15s, box-shadow 0.15s;
            box-sizing: border-box;
        }
        .field-item .remove-btn:hover, .field-item .remove-btn:active {
            background: #fee2e2;
            color: #b91c1c;
            box-shadow: 0 2px 8px #fca5a533;
        }

        /* Custom styles for the field lists to match image */
        .field-list-container {
            background-color: #f8fafc; /* bg-gray-50 */
            border-radius: 0.5rem; /* rounded-lg */
            padding: 1rem;
            box-shadow: inset 0 1px 3px 0 rgba(0, 0, 0, 0.05); /* subtle inner shadow */
            min-height: 120px; /* Ensure enough space for fields */
        }

        .selected-keys-dropzone {
            border: 2px dashed #93c5fd; /* blue-300 */
            background-color: #eff6ff; /* blue-50 */
            min-height: 80px;
            padding: 1rem;
            border-radius: 0.5rem;
        }
        .selected-keys-dropzone.drag-over {
            border-color: #3b82f6; /* blue-500 */
            background-color: #dbeafe; /* blue-100 */
        }

        /* Tab-like styling for preview tables */
        .tab-header {
            display: inline-block;
            padding: 0.5rem 1rem;
            border-top-left-radius: 0.5rem;
            border-top-right-radius: 0.5rem;
            background-color: #e2e8f0; /* bg-gray-200 */
            color: #4a5568; /* text-gray-700 */
            font-weight: 600;
            margin-bottom: -1px; /* Overlap with table border */
            border: 1px solid #cbd5e0; /* border-gray-300 */
            border-bottom: none;
        }
        .tab-header.active {
            background-color: #ffffff;
            border-color: #cbd5e0;
            color: #2d3748; /* text-gray-800 */
        }
    </style>
</head>
<body class="font-sans bg-gray-100 p-0 m-0 w-screen h-screen min-h-screen">
    <div id="globalMessage" style="display:none;position:fixed;top:20px;left:50%;transform:translateX(-50%);z-index:9999;min-width:200px;max-width:90vw;padding:12px 24px;background:#22c55e;color:#fff;font-size:16px;border-radius:8px;box-shadow:0 2px 8px rgba(0,0,0,0.08);text-align:center;"></div>
    <div class="w-screen h-screen min-h-screen bg-white shadow-lg rounded-none p-0 m-0 flex flex-col">
        <!-- 表关联配置区域 -->
        <div class="bg-gray-50 p-6 rounded-none shadow-sm mb-8 w-full">
            <div class="flex justify-between items-center mb-6">
                <h1 class="text-2xl font-bold text-gray-800">表关联配置</h1>
                <div class="flex space-x-3">
                    <a href="/query" class="px-4 py-2 bg-gray-500 text-white font-semibold rounded-lg shadow-md hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 transition duration-200">返回数据列表</a>
                    <button id="newComparisonBtn" class="px-4 py-2 bg-indigo-600 text-white font-semibold rounded-lg shadow-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition duration-200">
                        + 新建关联
                    </button>
                    <button id="saveComparisonBtn" class="px-4 py-2 bg-purple-600 text-white font-semibold rounded-lg shadow-md hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2 transition duration-200">
                        保存当前比对
                    </button>
                    <button id="deleteComparisonBtn" class="px-4 py-2 bg-red-600 text-white font-semibold rounded-lg shadow-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 transition duration-200">
                        删除当前比对
                    </button>
                    <div class="relative">
                        <select id="savedComparisonsSelect" class="block appearance-none w-full bg-white border border-gray-300 text-gray-700 py-2 px-4 pr-8 rounded-lg shadow-md leading-tight focus:outline-none focus:bg-white focus:border-gray-500 hover:border-gray-400 transition duration-200">
                            <option value="">选择已保存关联...</option>
                        </select>
                        <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
                            <svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/></svg>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 数据库连接配置区域 -->
            <div class="bg-white p-4 rounded-lg shadow-md border border-gray-200 mb-6">
                <h2 class="text-xl font-semibold text-gray-700 mb-3">数据库连接配置 (模拟)</h2>
                <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-4">
                    <div>
                        <label for="dbHost" class="block text-sm font-medium text-gray-700">主机:</label>
                        <input type="text" id="dbHost" value="localhost" class="mt-1 block w-full p-2 border border-gray-300 rounded-md text-sm">
                    </div>
                    <div>
                        <label for="dbPort" class="block text-sm font-medium text-gray-700">端口:</label>
                        <input type="text" id="dbPort" value="3306" class="mt-1 block w-full p-2 border border-gray-300 rounded-md text-sm">
                    </div>
                    <div>
                        <label for="dbUser" class="block text-sm font-medium text-gray-700">用户:</label>
                        <input type="text" id="dbUser" value="root" class="mt-1 block w-full p-2 border border-gray-300 rounded-md text-sm">
                    </div>
                    <div>
                        <label for="dbPassword" class="block text-sm font-medium text-gray-700">密码:</label>
                        <input type="password" id="dbPassword" value="123456" class="mt-1 block w-full p-2 border border-gray-300 rounded-md text-sm">
                    </div>
                    <div>
                        <label for="dbName" class="block text-sm font-medium text-gray-700">数据库名:</label>
                        <input type="text" id="dbName" value="jinxiaocun_db" class="mt-1 block w-full p-2 border border-gray-300 rounded-md text-sm">
                    </div>
                </div>
                <div class="text-center">
                    <button id="connectDbBtn" type="button" class="px-6 py-2 bg-green-600 text-white font-semibold rounded-lg shadow-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 transition duration-200">
                        连接数据库
                    </button>
                </div>
            </div>

            <div class="flex flex-col lg:flex-row gap-6">
                <!-- 左表配置 -->
                <div class="flex-1 bg-white p-4 rounded-lg shadow-md border border-gray-200">
                    <div class="flex justify-between items-center mb-3">
                        <h2 class="text-xl font-semibold text-gray-700">左表</h2>
                        <select id="leftTableSelect" class="p-1 border border-gray-300 rounded-md text-sm">
                            <option value="">请先连接数据库...</option>
                        </select>
                    </div>
                    <!-- 移除左表数据textarea -->
                    <!--<textarea id="tableAInput" rows="8" class="w-full p-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500 text-sm mb-4" placeholder="数据将从所选表格加载..." readonly></textarea>-->

                    <h3 class="text-md font-medium text-gray-700 mb-2">左表可用字段:</h3>
                    <div id="availableFieldsA" class="field-list-container flex flex-wrap gap-2 mb-4">
                        <!-- 可拖动字段将插入此处 -->
                    </div>

                    <h3 class="text-md font-medium text-gray-700 mb-2">左表已选关联字段 (拖放至此):</h3>
                    <div id="selectedKeysA" class="selected-keys-dropzone flex flex-wrap gap-2"
                         ondragover="allowDrop(event)" ondrop="handleDrop(event, 'A')"
                         ondragenter="this.classList.add('drag-over')" ondragleave="this.classList.remove('drag-over')">
                        <!-- 拖放字段将插入此处 -->
                    </div>
                </div>

                <!-- 右表配置 -->
                <div class="flex-1 bg-white p-4 rounded-lg shadow-md border border-gray-200">
                    <div class="flex justify-between items-center mb-3">
                        <h2 class="text-xl font-semibold text-gray-700">右表</h2>
                        <select id="rightTableSelect" class="p-1 border border-gray-300 rounded-md text-sm">
                            <option value="">请先连接数据库...</option>
                        </select>
                    </div>
                    <!-- 移除右表数据textarea -->
                    <!--<textarea id="tableBInput" rows="8" class="w-full p-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500 text-sm mb-4" placeholder="数据将从所选表格加载..." readonly></textarea>-->

                    <h3 class="text-md font-medium text-gray-700 mb-2">右表可用字段:</h3>
                    <div id="availableFieldsB" class="field-list-container flex flex-wrap gap-2 mb-4">
                        <!-- 可拖动字段将插入此处 -->
                    </div>

                    <h3 class="text-md font-medium text-gray-700 mb-2">右表已选关联字段 (拖放至此):</h3>
                    <div id="selectedKeysB" class="selected-keys-dropzone flex flex-wrap gap-2"
                         ondragover="allowDrop(event)" ondrop="handleDrop(event, 'B')"
                         ondragenter="this.classList.add('drag-over')" ondragleave="this.classList.remove('drag-over')">
                        <!-- 拖放字段将插入此处 -->
                    </div>
                </div>
            </div>

            <div class="text-center mt-6">
                <button id="applyAssociationBtn" class="px-8 py-3 bg-blue-600 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition duration-200 text-lg">
                    应用关联
                </button>
                <button id="showOutputResultsBtn" class="px-8 py-3 bg-blue-600 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition duration-200 text-lg">
                    输出结果
                </button>
            </div>
        </div>

        <!-- 数据预览和比对结果区域 -->
        <div class="bg-white p-6 rounded-lg shadow-lg">
            <h2 class="text-2xl font-bold text-gray-800 mb-6 text-center">数据展示</h2>

            <!-- 原始数据预览区域 -->
            <div class="flex flex-col lg:flex-row gap-6 mb-8">
                <div class="flex-1 bg-gray-50 rounded-lg shadow-sm overflow-x-auto border border-gray-200">
                    <div class="tab-header active" id="leftPreviewTab">左表预览</div>
                    <div id="tableAPreview" class="w-full text-sm p-4"></div>
                </div>
                <div class="flex-1 bg-gray-50 rounded-lg shadow-sm overflow-x-auto border border-gray-200">
                    <div class="tab-header active" id="rightPreviewTab">右表预览</div>
                    <div id="tableBPreview" class="w-full text-sm p-4"></div>
                </div>
            </div>

            <!-- 比对结果区域 -->
            <div class="bg-gray-50 p-4 rounded-lg shadow-sm overflow-x-auto border border-gray-200">
                <div class="flex justify-between items-center mb-3">
                    <h2 class="text-xl font-semibold text-gray-700">比对结果</h2>
                    <button onclick="exportComparisonResultsHTML()" class="px-4 py-2 bg-blue-600 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition duration-200 ml-2">导出</button>
                </div>
                <div id="comparisonResults" class="w-full text-sm">
                    <p class="text-gray-500 text-center py-4">点击"应用关联"按钮查看结果。</p>
                </div>
            </div>

            <!--  输出结果展示区域 -->
            <div class="bg-gray-50 p-4 rounded-lg shadow-sm overflow-x-auto border border-gray-200">
                <h2 class="text-xl font-semibold text-gray-700 mb-3">输出结果</h2>
                <div id="showOutputResults" class="w-full text-sm">
                    <p class="text-gray-500 text-center py-4">点击"输出结果"按钮查看结果。</p>
                </div>
            </div>
        </div>
    </div>

            <script>
            // Global variables for parsed data and selected keys
            let dataA = [];
            let dataB = [];
            let allHeaders = [];
            let currentKeyAFields = [];
            let currentKeyBFields = [];

            // 输出结果分页相关变量
            let outputPage = 1;
            let outputPerPage = 500; // 默认每页500条
            let outputTotalPages = 1;
            let outputAllData = { fields: [], rows: [] };
            let outputFilteredData = [];

            // 加载输出结果数据
            window.loadOutputResults = async function() {
                const tableDiv = document.getElementById('showOutputResults');
                tableDiv.innerHTML = '<div class="text-blue-500 text-center py-4">正在加载...</div>';
                try {
                    const resp = await fetch('/api/output_results');
                    const data = await resp.json();
                    if (!data.fields || !data.rows) throw new Error('数据格式错误');
                    
                    // 保存所有数据，使用后端返回的字段顺序
                    outputAllData = data;
                    outputFilteredData = data.rows;
                    outputPage = 1;
                    
                    // 后端已经计算了赠品金额，不需要前端重复计算

                    // 渲染输出结果界面
                    renderOutputResults();
                } catch (e) {
                    tableDiv.innerHTML = `<div class="text-red-500 text-center py-4">加载失败：${e.message}</div>`;
                }
            }

            // 渲染输出结果界面（包含查询条件和分页）
            window.renderOutputResults = function() {
                const tableDiv = document.getElementById('showOutputResults');
                
                // 构建查询条件区域
                let html = '<div class="mb-4">';
                html += '<div class="bg-white p-4 rounded-lg shadow-sm border border-gray-200 mb-4">';
                html += '<h3 class="text-lg font-semibold text-gray-700 mb-3">查询条件</h3>';
                html += '<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">';
                
                // 为每个字段创建查询输入框
                outputAllData.fields.forEach((field, index) => {
                    // 取当前输入框的值（如果有）
                    let filterVal = '';
                    const oldInput = document.getElementById(`filter_${index}`);
                    if (oldInput) filterVal = oldInput.value;
                    html += `<div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">${field}</label>
                        <input type="text" id="filter_${index}" placeholder="输入${field}查询条件" 
                               value="${filterVal.replace(/"/g, '&quot;')}"
                               class="w-full p-2 border border-gray-300 rounded-md text-sm focus:ring-blue-500 focus:border-blue-500">
                    </div>`;
                });
                
                html += '</div>';
                html += '<div class="flex justify-between items-center">';
                html += '<button onclick="applyOutputFilters()" class="px-4 py-2 bg-blue-600 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition duration-200">查询</button>';
                html += '<button onclick="clearOutputFilters()" class="px-4 py-2 bg-gray-500 text-white font-semibold rounded-lg shadow-md hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 transition duration-200">清空条件</button>';
                html += '<button onclick="exportOutputResults()" class="px-4 py-2 bg-green-600 text-white font-semibold rounded-lg shadow-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 transition duration-200 ml-2">导出</button>';
                html += '</div>';
                html += '</div>';
                
                // 构建分页控件
                const total = outputFilteredData.length;
                outputTotalPages = Math.max(1, Math.ceil(total / outputPerPage));
                
                html += '<div class="flex justify-between items-center mb-4">';
                html += `<div class="text-sm text-gray-600">共 ${total} 条记录，第 ${outputPage} / ${outputTotalPages} 页</div>`;
                html += '<div class="flex items-center gap-2">';
                html += `<button class="px-3 py-1 border rounded ${outputPage<=1?'bg-gray-200 text-gray-400':'bg-white hover:bg-gray-50'}" ${outputPage<=1?'disabled':''} onclick="changeOutputPage(1)">首页</button>`;
                html += `<button class="px-3 py-1 border rounded ${outputPage<=1?'bg-gray-200 text-gray-400':'bg-white hover:bg-gray-50'}" ${outputPage<=1?'disabled':''} onclick="changeOutputPage(${outputPage-1})">上一页</button>`;
                html += `<span class="px-3 py-1">${outputPage} / ${outputTotalPages}</span>`;
                html += `<button class="px-3 py-1 border rounded ${outputPage>=outputTotalPages?'bg-gray-200 text-gray-400':'bg-white hover:bg-gray-50'}" ${outputPage>=outputTotalPages?'disabled':''} onclick="changeOutputPage(${outputPage+1})">下一页</button>`;
                html += `<button class="px-3 py-1 border rounded ${outputPage>=outputTotalPages?'bg-gray-200 text-gray-400':'bg-white hover:bg-gray-50'}" ${outputPage>=outputTotalPages?'disabled':''} onclick="changeOutputPage(${outputTotalPages})">末页</button>`;
                html += `<select id="outputPerPageSelect" class="ml-2 border rounded px-2 py-1" onchange="changeOutputPerPage()">
                            <option value="500" ${outputPerPage==500?'selected':''}>500/页</option>
                            <option value="1000" ${outputPerPage==1000?'selected':''}>1000/页</option>
                        </select>`;
                html += '</div>';
                html += '</div>';
                
                // 构建数据表格
                html += '<div class="overflow-x-auto">';
                html += '<table class="min-w-full bg-white border border-gray-200 rounded-md overflow-hidden">';
                html += '<thead><tr class="bg-blue-50">';
                outputAllData.fields.forEach(field => {
                    html += `<th class="px-3 py-2 border-b text-left text-xs font-semibold text-gray-700 uppercase tracking-wider">${field}</th>`;
                });
                html += '</tr></thead><tbody>';
                
                // 计算当前页的数据
                const startIdx = (outputPage - 1) * outputPerPage;
                const endIdx = Math.min(startIdx + outputPerPage, outputFilteredData.length);
                const currentPageData = outputFilteredData.slice(startIdx, endIdx);
                
                currentPageData.forEach(row => {
                    html += '<tr class="hover:bg-gray-50">';
                    outputAllData.fields.forEach(field => {
                        html += `<td class="px-3 py-2 border-b text-sm">${row[field] ?? ''}</td>`;
                    });
                    html += '</tr>';
                });
                
                html += '</tbody></table>';
                html += '</div>';
                
                tableDiv.innerHTML = html;
            }

            // 应用查询条件
            window.applyOutputFilters = function() {
                const filters = {};
                outputAllData.fields.forEach((field, index) => {
                    const value = document.getElementById(`filter_${index}`).value.trim();
                    if (value) {
                        filters[field] = value.toLowerCase();
                    }
                });
                
                // 过滤数据
                outputFilteredData = outputAllData.rows.filter(row => {
                    return Object.keys(filters).every(field => {
                        const cellValue = (row[field] || '').toString().toLowerCase();
                        return cellValue.includes(filters[field]);
                    });
                });
                
                outputPage = 1; // 重置到第一页
                renderOutputResults();
            }

            // 清空查询条件
            window.clearOutputFilters = function() {
                outputAllData.fields.forEach((field, index) => {
                    const input = document.getElementById(`filter_${index}`);
                    if (input) input.value = '';
                });
                
                outputFilteredData = outputAllData.rows;
                outputPage = 1;
                renderOutputResults();
            }

            // 切换输出结果页面
            window.changeOutputPage = function(page) {
                outputPage = Math.max(1, Math.min(page, outputTotalPages));
                renderOutputResults();
            }

            // 切换输出结果每页显示数量
            window.changeOutputPerPage = function() {
                const sel = document.getElementById('outputPerPageSelect');
                outputPerPage = parseInt(sel.value);
                outputPage = 1;
                renderOutputResults();
            }

            window.exportOutputResults = function() {
                if (!outputAllData.fields || !outputFilteredData) return;
                // 过滤掉id字段
                const exportFields = outputAllData.fields.filter(f => f !== 'id');
                let csv = exportFields.join(',') + '\n';
                outputFilteredData.forEach(row => {
                    csv += exportFields.map(f => {
                        let val = row[f] ?? '';
                        // 转义逗号和引号
                        if (typeof val === 'string' && (val.includes(',') || val.includes('"') || val.includes('\n'))) {
                            val = '"' + val.replace(/"/g, '""') + '"';
                        }
                        return val;
                    }).join(',') + '\n';
                });
                // 生成下载
                const blob = new Blob([csv], {type: 'text/csv'});
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = 'output_results.csv';
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
            }

        // ========== 新增：全局数据库配置缓存 ==========
        let currentDbConfig = null;

        // ========== 比对结果分页相关 ==========
        let comparePage = 1;
        let comparePerPage = 500;
        let compareTotalPages = 1;
        let compareRowsCache = [];

        // ========== 替换为真实后端API ===========
        async function fetchDatabaseTables(dbConfig) {
            const response = await fetch('/api/get_tables', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(dbConfig)
            });
            const data = await response.json();
            if (response.ok) return data.tables;
            throw new Error(data.error || '获取表失败');
        }

        async function fetchTableData(tableName, dbConfig) {
            const response = await fetch('/api/get_table_data', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ table: tableName, dbconf: dbConfig })
            });
            const data = await response.json();
            if (response.ok) return data.csv_string;
            throw new Error(data.error || '获取表数据失败');
        }

        // ========== 替换模拟函数 ===========
        // mockFetchDatabaseTables → fetchDatabaseTables
        // mockFetchTableData → fetchTableData

        // Helper function: Parse CSV string to array of objects
        function parseCSV(csvString) {
            const lines = csvString.trim().split('\n');
            if (lines.length === 0) return { headers: [], data: [] };

            const headers = lines[0].split(',').map(h => h.trim());
            const data = [];
            for (let i = 1; i < lines.length; i++) {
                const values = lines[i].split(',').map(v => v.trim());
                if (values.length !== headers.length) {
                    console.warn(`Skipping malformed row: ${lines[i]}`);
                    continue;
                }
                const row = {};
                headers.forEach((header, index) => {
                    row[header] = values[index];
                });
                data.push(row);
            }
            return { headers, data };
        }

        // 左右表预览显示数据，只显示已选关联字段，前5条
        function renderTablePreview(data, element, selectedFields) {
            if (!data || data.length === 0 || !selectedFields || selectedFields.length === 0) {
                element.innerHTML = '<p class="text-gray-500 text-center py-2">无数据可预览。</p>';
                return;
            }
            let tableHtml = '<table class="min-w-full bg-white border border-gray-200 rounded-md overflow-hidden">';
            tableHtml += '<thead><tr class="bg-header">';
            selectedFields.forEach(header => {
                tableHtml += `<th class="py-2 px-4 border-b border-gray-200 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">${header}</th>`;
            });
            tableHtml += '</tr></thead>';
            tableHtml += '<tbody>';
            data.slice(0, 5).forEach(row => {
                tableHtml += '<tr class="hover:bg-gray-50">';
                selectedFields.forEach(header => {
                    tableHtml += `<td class="py-2 px-4 border-b border-gray-200">${row[header] || ''}</td>`;
                });
                tableHtml += '</tr>';
            });
            tableHtml += '</tbody></table>';
            element.innerHTML = tableHtml;
        }
        // 在updateFieldDisplays后渲染左右表预览
        function updateFieldDisplays() {
            const headersA = dataA.length > 0 ? Object.keys(dataA[0]) : [];
            const headersB = dataB.length > 0 ? Object.keys(dataB[0]) : [];
            populateAvailableFields(headersA, 'A');
            populateSelectedKeys(currentKeyAFields, 'A');
            populateAvailableFields(headersB, 'B');
            populateSelectedKeys(currentKeyBFields, 'B');
            // 启用拖拽排序
            enableDragSort('selectedKeysA', currentKeyAFields, null);
            enableDragSort('selectedKeysB', currentKeyBFields, null);
            // 支持空白区域拖入
            enableDropToSelected('selectedKeysA', 'A');
            enableDropToSelected('selectedKeysB', 'B');
            // 渲染左右表预览
            const tableAPreview = document.getElementById('tableAPreview');
            const tableBPreview = document.getElementById('tableBPreview');
            if (tableAPreview) renderTablePreview(dataA, tableAPreview, currentKeyAFields);
            if (tableBPreview) renderTablePreview(dataB, tableBPreview, currentKeyBFields);
        }

        // 日期格式化函数，转为yyyy/M/d
        function formatDateToYMD(val) {
            if (!val) return '';
            let d = new Date(val.replace(/-/g,'/').replace(/\./g,'/'));
            if (isNaN(d.getTime())) return val;
            return d.getFullYear() + '/' + (d.getMonth()+1) + '/' + d.getDate();
        }

        // 修改isMatch函数，针对customer_flow的进货日期和customer_redemption_details的业务日期做格式化后比较
        function isMatch(rowA, rowB, keysA, keysB, tableAName, tableBName) {
            for (let i = 0; i < keysA.length; i++) {
                let valA = rowA[keysA[i]];
                let valB = rowB[keysB[i]];
                // 特殊处理
                if ((tableAName === 'customer_flow' && keysA[i] === '进货日期') || (tableBName === 'customer_flow' && keysB[i] === '进货日期')) {
                    valA = (keysA[i] === '进货日期') ? formatDateToYMD(valA) : valA;
                    valB = (keysB[i] === '进货日期') ? formatDateToYMD(valB) : valB;
                }
                if ((tableAName === 'customer_redemption_details' && keysA[i] === '业务日期') || (tableBName === 'customer_redemption_details' && keysB[i] === '业务日期')) {
                    valA = (keysA[i] === '业务日期') ? formatDateToYMD(valA) : valA;
                    valB = (keysB[i] === '业务日期') ? formatDateToYMD(valB) : valB;
                }
                if (valA !== valB) {
                    return false;
                }
            }
            return true;
        }

        // 新增：后端join比对接口调用
        async function fetchCompareJoin(tableA, tableB, keysA, keysB, dbconf, date_fields) {
            const resp = await fetch('/api/compare_join', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    tableA, tableB, keysA, keysB, dbconf, date_fields
                })
            });
            const data = await resp.json();
            if (!resp.ok) throw new Error(data.error || '后端比对失败');
            if (data.sql) console.log('[后端JOIN SQL]', data.sql);
            return data.csv_string;
        }

        // 渲染分页控件
        function renderComparePagination(container, total, page, perPage, onPageChange) {
            compareTotalPages = Math.max(1, Math.ceil(total / perPage));
            let html = '<div class="flex justify-between items-center mb-2">';
            html += `<div>共 ${total} 条，比对字段：<span class='font-bold text-blue-600'>${[...new Set([...currentKeyAFields, ...currentKeyBFields])].join(', ')}</span></div>`;
            html += '<div class="flex items-center gap-2">';
            html += `<button class="px-2 py-1 border rounded ${page<=1?'bg-gray-200 text-gray-400':'bg-white'}" ${page<=1?'disabled':''} onclick="changeComparePage(1)">首页</button>`;
            html += `<button class="px-2 py-1 border rounded ${page<=1?'bg-gray-200 text-gray-400':'bg-white'}" ${page<=1?'disabled':''} onclick="changeComparePage(${page-1})">上一页</button>`;
            html += `<span>第 ${page} / ${compareTotalPages} 页</span>`;
            html += `<button class="px-2 py-1 border rounded ${page>=compareTotalPages?'bg-gray-200 text-gray-400':'bg-white'}" ${page>=compareTotalPages?'disabled':''} onclick="changeComparePage(${page+1})">下一页</button>`;
            html += `<button class="px-2 py-1 border rounded ${page>=compareTotalPages?'bg-gray-200 text-gray-400':'bg-white'}" ${page>=compareTotalPages?'disabled':''} onclick="changeComparePage(${compareTotalPages})">末页</button>`;
            html += `<select id="comparePerPageSelect" class="ml-2 border rounded" onchange="changeComparePerPage()">
                        <option value="500" ${perPage==500?'selected':''}>500/页</option>
                        <option value="1000" ${perPage==1000?'selected':''}>1000/页</option>
                    </select>`;
            html += '</div></div>';
            container.innerHTML = html;
        }
        function changeComparePage(page) {
            comparePage = Math.max(1, Math.min(page, compareTotalPages));
            renderCompareTable(compareRowsCache, document.getElementById('comparisonResults'));
        }
        function changeComparePerPage() {
            const sel = document.getElementById('comparePerPageSelect');
            comparePerPage = parseInt(sel.value);
            comparePage = 1;
            renderCompareTable(compareRowsCache, document.getElementById('comparisonResults'));
        }

        // 表名中英文映射（需与后端保持一致）
        const tableNameMap = {
            'customer_redemption_details': '客户原始兑付明细',
            'customer_flow': '仲景宛西',
            'activity_plan': '活动方案',
            'output_results': '输出结果'
        };

        // 比对结果区域渲染，显示所有字段，支持分页，左右表分割线
        function renderCompareTable(rows, container) {
            window.compareRowsCache = rows || [];
            if (!container) return;
            container.innerHTML = '';
            if (!rows || rows.length === 0) {
                container.innerHTML = '<p class="text-gray-500 text-center py-4">无比对结果。</p>';
                return;
            }
            // 分页参数
            const pageSize = 500;
            const total = rows.length;
            const totalPages = Math.max(1, Math.ceil(total / pageSize));
            window.comparePage = window.comparePage || 1;
            if (window.comparePage > totalPages) window.comparePage = totalPages;
            const startIdx = (window.comparePage - 1) * pageSize;
            const endIdx = Math.min(startIdx + pageSize, total);
            const pageRows = rows.slice(startIdx, endIdx);
            // 获取所有可能的字段，过滤掉ID字段
            let allFields = [];
            rows.forEach(row => {
                if (row.data) {
                    Object.keys(row.data).forEach(key => {
                        // 过滤掉左ID和右ID字段
                        if (!key.includes('左id') && !key.includes('右id') && 
                            !key.includes('左-id') && !key.includes('右-id') &&
                            !key.includes('左_id') && !key.includes('右_id') &&
                            !allFields.includes(key)) {
                            allFields.push(key);
                        }
                    });
                }
            });
            
            // 如果没有字段信息，尝试从第一个匹配的行获取
            if (allFields.length === 0 && rows.length > 0) {
                const matchedRow = rows.find(row => row.type === 'matched');
                if (matchedRow && matchedRow.data) {
                    allFields = Object.keys(matchedRow.data);
                }
            }
            
            // 如果还是没有字段信息，使用默认字段
            if (allFields.length === 0) {
                allFields = window.compareFields || [];
            }
            let splitIdx = 0;
            for (let i = 0; i < allFields.length; i++) {
                if (allFields[i].startsWith('右')) { splitIdx = i; break; }
            }
            // 横向滚动条容器包裹分页和表格
            let tableHtml = '<div style="overflow-x:auto;width:100%;">';
            // 只保留一套分页控件
            tableHtml += `<div style=\"margin:16px 0;display:flex;justify-content:center;align-items:center;gap:10px;\">`;
            tableHtml += `<button onclick=\"window.comparePage=1;renderCompareTable(window.compareRowsCache,document.getElementById('comparisonResults'))\" ${window.comparePage===1?'disabled':''}>首页</button>`;
            tableHtml += `<button onclick=\"window.comparePage=Math.max(1,window.comparePage-1);renderCompareTable(window.compareRowsCache,document.getElementById('comparisonResults'))\" ${window.comparePage===1?'disabled':''}>上一页</button>`;
            tableHtml += `<span>第 ${window.comparePage} / ${totalPages} 页</span>`;
            tableHtml += `<button onclick=\"window.comparePage=Math.min(${totalPages},window.comparePage+1);renderCompareTable(window.compareRowsCache,document.getElementById('comparisonResults'))\" ${window.comparePage===totalPages?'disabled':''}>下一页</button>`;
            tableHtml += `<button onclick=\"window.comparePage=${totalPages};renderCompareTable(window.compareRowsCache,document.getElementById('comparisonResults'))\" ${window.comparePage===totalPages?'disabled':''}>末页</button>`;
            tableHtml += `<span style='margin-left:16px;'>共 ${total} 条</span>`;
            tableHtml += '</div>';
            tableHtml += '<table class="min-w-full bg-white border border-gray-200 rounded-md overflow-hidden">';
            tableHtml += '<thead><tr class="bg-header">';
            allFields.forEach((header, idx) => {
                let style = '';
                if (idx === splitIdx && splitIdx > 0) style = 'border-left:2px solid #888;';
                tableHtml += `<th class="py-2 px-4 border-b border-gray-200 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider" style="${style}">${header}</th>`;
            });
            tableHtml += '</tr></thead><tbody>';
            pageRows.forEach(row => {
                let rowClass = '';
                if(row.type==='matched') rowClass='bg-match';
                else if(row.type==='left_only') rowClass='bg-left-only';
                else if(row.type==='right_only') rowClass='bg-right-only';
                tableHtml += `<tr class="hover:bg-gray-50 ${rowClass}">`;
                allFields.forEach((header, idx) => {
                    let style = '';
                    if (idx === splitIdx && splitIdx > 0) style = 'border-left:2px solid #888;';
                    let cellValue = '';
                    if (row.data && row.data[header] !== undefined) {
                        cellValue = row.data[header];
                    }
                    tableHtml += `<td class="py-2 px-4 border-b border-gray-200" style="${style}">${cellValue}</td>`;
                });
                tableHtml += '</tr>';
            });
            tableHtml += '</tbody></table>';
            tableHtml += '</div>';
            container.innerHTML = tableHtml;
        }

        // 修改performComparison，调用renderCompareTable时重置comparePage
        async function performComparison() {
            const comparisonResults = document.getElementById('comparisonResults');
            if (dataA.length === 0 && dataB.length === 0) {
                comparisonResults.innerHTML = '<p class="text-red-500 text-center py-4">请先加载数据！</p>';
                return;
            }
            const keyAFields = currentKeyAFields;
            const keyBFields = currentKeyBFields;
            if (keyAFields.length === 0 || keyBFields.length === 0) {
                comparisonResults.innerHTML = '<p class="text-red-500 text-center py-4">请拖动字段到"已选关联字段"区域以指定关联字段！</p>';
                return;
            }
            if (keyAFields.length !== keyBFields.length) {
                comparisonResults.innerHTML = '<p class="text-red-500 text-center py-4">表A和表B的关联字段数量必须一致！</p>';
                return;
            }
            // 获取表名
            const tableAName = document.getElementById('leftTableSelect')?.value || '';
            const tableBName = document.getElementById('rightTableSelect')?.value || '';
            // 判断是否需要日期格式化
            let date_fields = {};
            if ((tableAName === 'customer_flow' && keyAFields.includes('进货日期')) && (tableBName === 'customer_redemption_details' && keyBFields.includes('业务日期'))) {
                date_fields = {A: '进货日期', B: '业务日期'};
            } else if ((tableAName === 'customer_redemption_details' && keyAFields.includes('业务日期')) && (tableBName === 'customer_flow' && keyBFields.includes('进货日期'))) {
                date_fields = {A: '业务日期', B: '进货日期'};
            }
            // 优先用后端join
            let matchedRows = [];
            try {
                comparisonResults.innerHTML = '<p class="text-blue-500 text-center py-4">正在请求后端比对...</p>';
                const csv = await fetchCompareJoin(tableAName, tableBName, keyAFields, keyBFields, currentDbConfig, date_fields);
                // 解析csv并渲染
                const result = parseCSV(csv);
                if (result.data && result.data.length > 0) {
                    matchedRows = result.data.map(row => ({type: 'matched', data: row}));
                }
            } catch (e) {
                comparisonResults.innerHTML = `<p class='text-red-500 text-center py-4'>后端比对失败：${e.message}，将尝试前端比对...</p>`;
            }
            // 前端补充left_only/right_only
            const matchedBIndices = new Set();
            const leftOnlyRows = [];
            const rightOnlyRows = [];
            
            // 构建完整的字段列表，用于left_only和right_only行
            let allFields = [];
            if (matchedRows.length > 0 && matchedRows[0].data) {
                allFields = Object.keys(matchedRows[0].data);
            }
            
            // 先用前端逻辑找出left_only/right_only
            dataA.forEach((rowA, idxA) => {
                let matched = false;
                for (let i = 0; i < dataB.length; i++) {
                    const rowB = dataB[i];
                    if (isMatch(rowA, rowB, keyAFields, keyBFields, tableAName, tableBName)) {
                        matched = true;
                        matchedBIndices.add(i);
                        break;
                    }
                }
                if (!matched) {
                    // 为left_only行构建完整的数据结构
                    let leftOnlyData = {};
                    if (allFields.length > 0) {
                        allFields.forEach(field => {
                            if (field.startsWith('左-')) {
                                // 移除"左-"前缀，从rowA中获取数据
                                const originalField = field.substring(2);
                                leftOnlyData[field] = rowA[originalField] || '';
                            } else if (field.startsWith('右-')) {
                                // 右表字段设为空
                                leftOnlyData[field] = '';
                            } else {
                                // 其他字段从rowA中获取
                                leftOnlyData[field] = rowA[field] || '';
                            }
                        });
                    } else {
                        // 如果没有完整的字段列表，直接使用rowA的数据
                        leftOnlyData = {...rowA};
                    }
                    leftOnlyRows.push({type: 'left_only', data: leftOnlyData});
                }
            });
            
            dataB.forEach((rowB, idxB) => {
                if (!matchedBIndices.has(idxB)) {
                    // 为right_only行构建完整的数据结构
                    let rightOnlyData = {};
                    if (allFields.length > 0) {
                        allFields.forEach(field => {
                            if (field.startsWith('右-')) {
                                // 移除"右-"前缀，从rowB中获取数据
                                const originalField = field.substring(2);
                                rightOnlyData[field] = rowB[originalField] || '';
                            } else if (field.startsWith('左-')) {
                                // 左表字段设为空
                                rightOnlyData[field] = '';
                            } else {
                                // 其他字段从rowB中获取
                                rightOnlyData[field] = rowB[field] || '';
                            }
                        });
                    } else {
                        // 如果没有完整的字段列表，直接使用rowB的数据
                        rightOnlyData = {...rowB};
                    }
                    rightOnlyRows.push({type: 'right_only', data: rightOnlyData});
                }
            });
            // 合并，先matched再left_only再right_only
            const allRows = [...matchedRows, ...leftOnlyRows, ...rightOnlyRows];
            if (allRows.length === 0) {
                comparisonResults.innerHTML = '<p class="text-red-500 text-center py-4">无比对结果。</p>';
                return;
            }
            comparePage = 1;
            renderCompareTable(allRows, comparisonResults);
            
            // 自动切换到比对结果视图
            const previewSection = document.querySelector('.flex.flex-col.lg\\:flex-row.gap-6.mb-8');
            const outputSection = document.querySelector('.bg-gray-50.p-4.rounded-lg.shadow-sm.overflow-x-auto.border.border-gray-200:last-child');
            
            if (previewSection) {
                previewSection.style.display = 'none';
            }
            if (outputSection) {
                outputSection.style.display = 'none';
            }
            
            // 比对结果区域已经在显示，不需要隐藏
            
            // 记录当前视图状态
            window.currentView = 'comparison';
            
            // 确保比对结果区域可见
            const comparisonSection = document.querySelector('.bg-gray-50.p-4.rounded-lg.shadow-sm.overflow-x-auto.border.border-gray-200');
            if (comparisonSection) {
                comparisonSection.style.display = 'block';
            }
        }

        // Event listener: Save current comparison
        function saveCurrentComparison() {
            const name = prompt("请输入保存的比对名称:");
            if (name) {
                const comparisons = JSON.parse(localStorage.getItem('savedComparisons') || '[]');
                comparisons.push({
                    name: name,
                    tableAName: document.getElementById('leftTableSelect').value, // Save table names
                    tableBName: document.getElementById('rightTableSelect').value,
                    keyAFields: currentKeyAFields,
                    keyBFields: currentKeyBFields
                });
                localStorage.setItem('savedComparisons', JSON.stringify(comparisons));
                alert(`比对 "${name}" 已保存！`);
                loadSavedComparisons(); // Reload dropdown after saving
            }
        }

        // Load saved comparisons list to dropdown
        function loadSavedComparisons() {
            const comparisons = JSON.parse(localStorage.getItem('savedComparisons') || '[]');
            const savedComparisonsSelect = document.getElementById('savedComparisonsSelect');
            if (!savedComparisonsSelect) {
                console.error("Saved comparisons select element not found!");
                return;
            }
            savedComparisonsSelect.innerHTML = '<option value="">选择已保存关联...</option>';
            comparisons.forEach((comp, index) => {
                const option = document.createElement('option');
                option.value = index;
                option.textContent = comp.name;
                savedComparisonsSelect.appendChild(option);
            });
        }

        // Event listener: Select and load saved comparison
        async function loadSelectedComparison(event) {
            const selectedIndex = event.target.value;
            if (selectedIndex !== "") {
                const comparisons = JSON.parse(localStorage.getItem('savedComparisons') || '[]');
                const selectedComp = comparisons[parseInt(selectedIndex)];
                if (selectedComp) {
                    // Set dropdowns first
                    const leftTableSelect = document.getElementById('leftTableSelect');
                    const rightTableSelect = document.getElementById('rightTableSelect');
                    if (leftTableSelect) leftTableSelect.value = selectedComp.tableAName || '';
                    if (rightTableSelect) rightTableSelect.value = selectedComp.tableBName || '';

                    // Set currentKeyAFields and currentKeyBFields from the loaded comparison FIRST
                    currentKeyAFields = selectedComp.keyAFields || [];
                    currentKeyBFields = selectedComp.keyBFields || [];

                    console.log("Loaded saved fields A (before loadTableData):", currentKeyAFields);
                    console.log("Loaded saved fields B (before loadTableData):", currentKeyBFields);

                    // Load data based on selected table names using mockFetchTableData
                    await loadTableData('A', selectedComp.tableAName);
                    await loadTableData('B', selectedComp.tableBName);

                    console.log("Loaded saved fields A (after loadTableData):", currentKeyAFields);
                    console.log("Loaded saved fields B (after loadTableData):", currentKeyBFields);

                    updateFieldDisplays(); // Ensure available and selected fields are correctly rendered

                    // Perform comparison after everything is set up
                    setTimeout(() => {
                        performComparison();
                    }, 100);
                }
            }
        }

        // Event listener: New comparison
        function newComparison() {
            const tableAInput = document.getElementById('tableAInput');
            const tableBInput = document.getElementById('tableBInput');
            const leftTableSelect = document.getElementById('leftTableSelect');
            const rightTableSelect = document.getElementById('rightTableSelect');
            const leftPreviewTab = document.getElementById('leftPreviewTab');
            const rightPreviewTab = document.getElementById('rightPreviewTab');
            const tableAPreview = document.getElementById('tableAPreview');
            const tableBPreview = document.getElementById('tableBPreview');
            const comparisonResults = document.getElementById('comparisonResults');
            const savedComparisonsSelect = document.getElementById('savedComparisonsSelect');

            if (tableAInput) tableAInput.value = '';
            if (tableBInput) tableBInput.value = '';
            if (leftTableSelect) leftTableSelect.value = ''; // Reset dropdown
            if (rightTableSelect) rightTableSelect.value = ''; // Reset dropdown
            if (leftPreviewTab) leftPreviewTab.textContent = '左表预览'; // Reset tab name
            if (rightPreviewTab) rightPreviewTab.textContent = '右表预览'; // Reset tab name

            dataA = [];
            dataB = [];
            currentKeyAFields = [];
            currentKeyBFields = [];
            allHeaders = [];
            updateFieldDisplays();
            if (tableAPreview) tableAPreview.innerHTML = '<p class="text-gray-500 text-center py-2">无数据可预览。</p>';
            if (tableBPreview) tableBPreview.innerHTML = '<p class="text-gray-500 text-center py-2">无数据可预览。</p>';
            if (comparisonResults) comparisonResults.innerHTML = '<p class="text-gray-500 text-center py-4">点击"应用关联"按钮查看结果。</p>';
            if (savedComparisonsSelect) savedComparisonsSelect.value = "";
        }

        // Function to load table data into input and preview based on table name
        async function loadTableData(type, tableName) {
            if (!tableName) {
                if (type === 'A') dataA = [];
                else dataB = [];
                updateFieldDisplays();
                return;
            }
            try {
                const csvString = await fetchTableData(tableName, currentDbConfig);
                const result = parseCSV(csvString);
                if (type === 'A') {
                    dataA = result.data;
                } else {
                    dataB = result.data;
                }
                updateFieldDisplays();
            } catch (error) {
                if (type === 'A') dataA = [];
                else dataB = [];
                updateFieldDisplays();
            }
        }

        // Populate available fields area
        function populateAvailableFields(headers, type) {
            const container = type === 'A' ? document.getElementById('availableFieldsA') : document.getElementById('availableFieldsB');
            if (!container) {
                console.error(`Container for available fields (${type}) not found!`);
                return;
            }
            container.innerHTML = '';
            const currentKeys = type === 'A' ? currentKeyAFields : currentKeyBFields;
            headers.forEach(header => {
                if (!currentKeys.includes(header)) {
                    container.appendChild(createDraggableField(header, false, type));
                }
            });
        }

        // Populate selected keys area
        function populateSelectedKeys(selectedFields, type) {
            const container = type === 'A' ? document.getElementById('selectedKeysA') : document.getElementById('selectedKeysB');
            if (!container) {
                console.error(`Container for selected keys (${type}) not found!`);
                return;
            }
            container.innerHTML = '';
            selectedFields.forEach(header => {
                container.appendChild(createDraggableField(header, true, type)); // true for selected
            });
        }

        // Helper function to create a draggable field item
        function createDraggableField(header, isSelected = false, type = 'A') {
            const fieldItem = document.createElement('div');
            fieldItem.className = `field-item ${isSelected ? 'bg-indigo-200' : ''}`; // Indicate selected fields
            fieldItem.draggable = true;
            fieldItem.setAttribute('data-header', header);
            fieldItem.setAttribute('data-type', isSelected ? 'selected' : 'available'); // Indicate type
            fieldItem.setAttribute('data-side', type); // 标记左右表

            const fieldText = document.createElement('span');
            fieldText.textContent = header;
            fieldItem.appendChild(fieldText);

            const removeBtn = document.createElement('button');
            removeBtn.type = 'button';
            removeBtn.className = 'remove-btn';
            removeBtn.textContent = '×';
            removeBtn.addEventListener('click', function(e) {
                e.stopPropagation();
                if (isSelected) {
                    const header = fieldItem.getAttribute('data-header');
                    if (type === 'A') {
                        currentKeyAFields = currentKeyAFields.filter(h => h !== header);
                    } else if (type === 'B') {
                        currentKeyBFields = currentKeyBFields.filter(h => h !== header);
                    }
                    updateFieldDisplays();
                }
            });
            fieldItem.appendChild(removeBtn);

            fieldItem.addEventListener('dragstart', dragStart);
            fieldItem.addEventListener('dragend', dragEnd);
            fieldItem.addEventListener('dragover', allowDrop);
            fieldItem.addEventListener('drop', handleDrop);
            fieldItem.addEventListener('click', toggleSelection);
            fieldItem.addEventListener('contextmenu', showContextMenu); // Right-click for removal

            return fieldItem;
        }

        // Drag and Drop functions
        function dragStart(event) {
            event.dataTransfer.setData("text/plain", event.target.getAttribute("data-header"));
            event.dataTransfer.setData("text/type", event.target.getAttribute("data-type"));
            event.target.classList.add('dragging');
        }

        function dragEnd(event) {
            event.target.classList.remove('dragging');
        }

        function allowDrop(event) {
            event.preventDefault();
        }

        function handleDrop(event, targetType) {
            event.preventDefault();
            const header = event.dataTransfer.getData("text/plain");
            const type = event.dataTransfer.getData("text/type");

            if (type === 'available' && targetType === 'selected') {
                addSelectedKey(header);
            } else if (type === 'selected' && targetType === 'available') {
                removeSelectedKey(header);
            }
        }

        function toggleSelection(event) {
            const fieldItem = event.target;
            const header = fieldItem.getAttribute("data-header");
            const type = fieldItem.getAttribute("data-type");

            if (type === 'available') {
                addSelectedKey(header);
            } else if (type === 'selected') {
                removeSelectedKey(header);
            }
        }

        function showContextMenu(event) {
            event.preventDefault();
            const fieldItem = event.target.closest('.field-item');
            if (!fieldItem) return;

            const header = fieldItem.getAttribute("data-header");
            const type = fieldItem.getAttribute("data-type");

            if (type === 'selected') {
                const confirm = confirm(`确定要从已选字段中移除 "${header}" 吗？`);
                if (confirm) {
                    removeSelectedKey(header);
                }
            }
        }

        function addSelectedKey(header) {
            if (!currentKeyAFields.includes(header) && !currentKeyBFields.includes(header)) {
                const fieldItem = createDraggableField(header, true);
                const selectedKeysContainer = document.getElementById('selectedKeysA'); // Default to A
                if (selectedKeysContainer.children.length > 0) {
                    selectedKeysContainer.insertBefore(fieldItem, selectedKeysContainer.firstChild);
                } else {
                    selectedKeysContainer.appendChild(fieldItem);
                }
                currentKeyAFields.push(header); // Assuming A for now, will be updated
                currentKeyBFields.push(header); // Assuming B for now, will be updated
                updateFieldDisplays();
            }
        }

        function removeSelectedKey(header) {
            const fieldItem = document.querySelector(`.field-item[data-header="${header}"]`);
            if (fieldItem) {
                fieldItem.remove();
                currentKeyAFields = currentKeyAFields.filter(h => h !== header);
                currentKeyBFields = currentKeyBFields.filter(h => h !== header);
                updateFieldDisplays();
            }
        }

        // Enable drag and drop sorting for selected keys（修正版，原生实现）
        function enableDragSort(containerId, fields, type) {
            const container = document.getElementById(containerId);
            if (!container) return;

            let draggedItem = null;

            // 先解绑所有事件，防止重复绑定
            container.querySelectorAll('.field-item').forEach(item => {
                item.ondragstart = null;
                item.ondragover = null;
                item.ondrop = null;
                item.ondragend = null;
            });

            container.querySelectorAll('.field-item').forEach(item => {
                item.ondragstart = function(e) {
                    draggedItem = item;
                    setTimeout(() => item.classList.add('dragging'), 0);
                };
                item.ondragend = function(e) {
                    item.classList.remove('dragging');
                    draggedItem = null;
                    // 拖拽结束后同步顺序
                    const newOrder = [];
                    container.querySelectorAll('.field-item').forEach(i => {
                        newOrder.push(i.getAttribute('data-header'));
                    });
                    if (containerId === 'selectedKeysA') {
                        currentKeyAFields = newOrder;
                    } else if (containerId === 'selectedKeysB') {
                        currentKeyBFields = newOrder;
                    }
                    updateFieldDisplays();
                };
                item.ondragover = function(e) {
                    e.preventDefault();
                    if (draggedItem && draggedItem !== item) {
                        container.insertBefore(draggedItem, item);
                    }
                };
                item.ondrop = function(e) {
                    e.preventDefault();
                    if (draggedItem && draggedItem !== item) {
                        container.insertBefore(draggedItem, item);
                    }
                };
            });
        }

        // 让"已选关联字段"容器支持空白区域拖入
        function enableDropToSelected(containerId, type) {
            const container = document.getElementById(containerId);
            if (!container) return;
            container.ondragover = function(e) {
                e.preventDefault();
            };
            container.ondrop = function(e) {
                e.preventDefault();
                // 只处理从可用字段拖入
                const header = e.dataTransfer.getData('text/plain');
                const dragType = e.dataTransfer.getData('text/type');
                if (dragType === 'available' && header) {
                    if (containerId === 'selectedKeysA' && !currentKeyAFields.includes(header)) {
                        currentKeyAFields.push(header);
                    } else if (containerId === 'selectedKeysB' && !currentKeyBFields.includes(header)) {
                        currentKeyBFields.push(header);
                    }
                    updateFieldDisplays();
                }
            };
        }

        // Function to handle database connection (mocked)
        async function connectToDatabase() {
            const dbConfig = {
                host: document.getElementById('dbHost').value,
                port: document.getElementById('dbPort').value,
                user: document.getElementById('dbUser').value,
                password: document.getElementById('dbPassword').value,
                database: document.getElementById('dbName').value
            };
            currentDbConfig = dbConfig; // 缓存
            console.log("Attempting to connect with config:", dbConfig);

            // Simulate connection success/failure
            try {
                // In a real app, you'd send dbConfig to your backend to establish connection
                await populateTableSelects();
                showGlobalMessage("数据库连接成功！已加载表格列表。");

                // Set default tables after connecting
                const leftTableSelect = document.getElementById('leftTableSelect');
                const rightTableSelect = document.getElementById('rightTableSelect');

                // 不再设置任何默认表名
                // 直接重置选择和数据
                newComparison();

                updateFieldDisplays();
                performComparison();


            } catch (error) {
                console.error("模拟数据库连接失败:", error);
                alert(`模拟数据库连接失败: ${error.message}`);
                newComparison(); // Reset UI on connection failure
            }
        }

        // Function to delete the currently selected comparison
        function deleteCurrentComparison() {
            const savedComparisonsSelect = document.getElementById('savedComparisonsSelect');
            if (!savedComparisonsSelect) {
                console.error("Saved comparisons select element not found for deletion!");
                return;
            }

            const selectedIndex = savedComparisonsSelect.value;
            if (selectedIndex === "" || isNaN(parseInt(selectedIndex))) {
                alert("请先从下拉框中选择一个要删除的比对。");
                return;
            }

            const comparisons = JSON.parse(localStorage.getItem('savedComparisons') || '[]');
            const comparisonName = comparisons[parseInt(selectedIndex)].name;

            // Using prompt for confirmation as alert/confirm are discouraged in some environments
            const confirmation = prompt(`确定要删除比对 "${comparisonName}" 吗？输入 '是' 确认。`);
            if (confirmation && confirmation.toLowerCase() === '是') {
                comparisons.splice(parseInt(selectedIndex), 1); // Remove the selected comparison
                localStorage.setItem('savedComparisons', JSON.stringify(comparisons));
                alert(`比对 "${comparisonName}" 已删除。`);
                loadSavedComparisons(); // Reload the dropdown
                newComparison(); // Reset the UI
            } else {
                alert("删除操作已取消。");
            }
        }

        // 获取所有表名并填充下拉框
        async function populateTableSelects() {
            const leftTableSelect = document.getElementById('leftTableSelect');
            const rightTableSelect = document.getElementById('rightTableSelect');
            if (!leftTableSelect || !rightTableSelect) {
                console.error("Table select dropdowns not found!");
                return;
            }
            leftTableSelect.innerHTML = '<option value="">选择表格...</option>';
            rightTableSelect.innerHTML = '<option value="">选择表格...</option>';
            try {
                const tables = await fetchDatabaseTables(currentDbConfig); // 传递当前配置
                tables.forEach(tableName => {
                    const cn = tableNameMap[tableName] || tableName;
                    const optionLeft = document.createElement('option');
                    optionLeft.value = tableName;
                    optionLeft.textContent = cn;
                    leftTableSelect.appendChild(optionLeft);

                    const optionRight = document.createElement('option');
                    optionRight.value = tableName;
                    optionRight.textContent = cn;
                    rightTableSelect.appendChild(optionRight);
                });
            } catch (error) {
                alert(`获取表格列表失败: ${error.message}`);
            }
        }

        function showGlobalMessage(msg, duration=2000) {
            const div = document.getElementById('globalMessage');
            if (!div) return;
            div.textContent = msg;
            div.style.display = 'block';
            clearTimeout(div._hideTimer);
            div._hideTimer = setTimeout(() => {
                div.style.display = 'none';
            }, duration);
        }

        function exportComparisonResults() {
            if (!window.compareRowsCache || !Array.isArray(window.compareRowsCache) || window.compareRowsCache.length === 0) {
                showGlobalMessage('暂无对比结果！');
                return;
            }
            // 用页面显示的字段顺序导出（后端返回的fields），过滤掉ID字段
            let allFields = window.compareFields || Object.keys(window.compareRowsCache[0]?.data || {});
            // 过滤掉ID字段
            allFields = allFields.filter(field => 
                !field.includes('左id') && !field.includes('右id') && 
                !field.includes('左-id') && !field.includes('右-id') &&
                !field.includes('左_id') && !field.includes('右_id')
            );
            let csv = allFields.join(',') + '\n';
            window.compareRowsCache.forEach(row => {
                csv += allFields.map(f => {
                    let val = row.data && row.data[f] !== undefined ? row.data[f] : '';
                    if (typeof val === 'string' && (val.includes(',') || val.includes('"') || val.includes('\n'))) {
                        val = '"' + val.replace(/"/g, '""') + '"';
                    }
                    return val;
                }).join(',') + '\n';
            });
            const blob = new Blob([csv], {type: 'text/csv'});
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'comparison_results.csv';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }

        function exportComparisonResultsHTML() {
            if (!window.compareRowsCache || !Array.isArray(window.compareRowsCache) || window.compareRowsCache.length === 0) {
                showGlobalMessage('暂无对比结果！');
                return;
            }
            // 用页面显示的字段顺序导出（后端返回的fields），过滤掉ID字段
            let allFields = window.compareFields || Object.keys(window.compareRowsCache[0]?.data || {});
            // 过滤掉ID字段
            allFields = allFields.filter(field => 
                !field.includes('左id') && !field.includes('右id') && 
                !field.includes('左-id') && !field.includes('右-id') &&
                !field.includes('左_id') && !field.includes('右_id')
            );
            let html = `<table border="1" cellspacing="0" cellpadding="4" style="border-collapse:collapse;font-size:14px;">`;
            html += `<tr style="background:#e2e8f0;font-weight:bold;">`;
            allFields.forEach(name => {
                html += `<th>${name}</th>`;
            });
            html += `</tr>`;
            window.compareRowsCache.forEach(row => {
                let bg = '';
                if (row.type === 'matched') bg = 'background:#d4edda;';
                if (row.type === 'left_only') bg = 'background:#f8d7da;';
                if (row.type === 'right_only') bg = 'background:#d1ecf1;';
                html += `<tr style="${bg}">`;
                allFields.forEach(f => {
                    let val = row.data && row.data[f] !== undefined ? row.data[f] : '';
                    html += `<td>${val}</td>`;
                });
                html += `</tr>`;
            });
            html += `</table>`;
            const blob = new Blob([`\uFEFF${html}`], {type: 'application/vnd.ms-excel'});
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'comparison_results.xls';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }

        // Page load initialization
        document.addEventListener('DOMContentLoaded', async () => {
            console.log("DOMContentLoaded fired.");

            // Get DOM elements
            const applyAssociationBtn = document.getElementById('applyAssociationBtn');
            const newComparisonBtn = document.getElementById('newComparisonBtn');
            const saveComparisonBtn = document.getElementById('saveComparisonBtn');
            const deleteComparisonBtn = document.getElementById('deleteComparisonBtn');
            const savedComparisonsSelect = document.getElementById('savedComparisonsSelect');
            const leftTableSelect = document.getElementById('leftTableSelect');
            const rightTableSelect = document.getElementById('rightTableSelect');
            const connectDbBtn = document.getElementById('connectDbBtn'); // New button
            const showOutputResultsBtn = document.getElementById("showOutputResultsBtn");

            console.log("applyAssociationBtn:", applyAssociationBtn);
            console.log("newComparisonBtn:", newComparisonBtn);
            console.log("saveComparisonBtn:", saveComparisonBtn);
            console.log("deleteComparisonBtn:", deleteComparisonBtn);
            console.log("savedComparisonsSelect:", savedComparisonsSelect);
            console.log("leftTableSelect:", leftTableSelect);
            console.log("rightTableSelect:", rightTableSelect);
            console.log("connectDbBtn:", connectDbBtn);
            console.log("showOutputResultsBtn:", showOutputResultsBtn);


            // Attach all event listeners
            if (applyAssociationBtn) {
                applyAssociationBtn.addEventListener('click', function() {
                    if (window.currentView === 'output') {
                        // 如果当前在输出结果视图，切换到比对结果视图
                        showComparisonView();
                    } else {
                        // 否则执行比对
                        performComparison();
                    }
                });
            } else console.error("applyAssociationBtn is null! Cannot attach event listener.");

            if (newComparisonBtn) newComparisonBtn.addEventListener('click', newComparison);
            else console.error("newComparisonBtn is null! Cannot attach event listener.");

            if (saveComparisonBtn) saveComparisonBtn.addEventListener('click', saveCurrentComparison);
            else console.error("saveComparisonBtn is null! Cannot attach event listener.");

            if (deleteComparisonBtn) deleteComparisonBtn.addEventListener('click', deleteCurrentComparison);
            else console.error("deleteComparisonBtn is null! Cannot attach event listener.");

            if (savedComparisonsSelect) savedComparisonsSelect.addEventListener('change', loadSelectedComparison);
            else console.error("savedComparisonsSelect is null! Cannot attach event listener.");

            if (leftTableSelect) leftTableSelect.addEventListener('change', async (event) => {
                await loadTableData('A', event.target.value);
                currentKeyAFields = []; // Clear selected keys when table changes
                updateFieldDisplays();
            });
            else console.error("leftTableSelect is null! Cannot attach event listener.");

            if (rightTableSelect) rightTableSelect.addEventListener('change', async (event) => {
                await loadTableData('B', event.target.value);
                currentKeyBFields = []; // Clear selected keys when table changes
                updateFieldDisplays();
            });
            else console.error("rightTableSelect is null! Cannot attach event listener.");

            // 修正连接按钮事件，阻止页面刷新
            const connectBtn = document.getElementById('connectDbBtn');
            if (connectBtn) {
                connectBtn.addEventListener('click', function(e) {
                    e.preventDefault(); // 阻止默认行为，防止刷新
                    connectToDatabase();
                });
            }

            document.getElementById('showOutputResultsBtn').onclick = async function() {
                // 隐藏原始数据预览区域和比对结果区域
                const previewSection = document.querySelector('.flex.flex-col.lg\\:flex-row.gap-6.mb-8');
                const comparisonSection = document.querySelector('.bg-gray-50.p-4.rounded-lg.shadow-sm.overflow-x-auto.border.border-gray-200');
                
                if (previewSection) {
                    previewSection.style.display = 'none';
                }
                if (comparisonSection) {
                    comparisonSection.style.display = 'none';
                }

                // 显示输出结果展示区域
                const outputSection = document.querySelector('.bg-gray-50.p-4.rounded-lg.shadow-sm.overflow-x-auto.border.border-gray-200:last-child');
                if (outputSection) {
                    outputSection.style.display = 'block';
                }

                // 记录当前视图状态
                window.currentView = 'output';

                // 加载数据
                await loadOutputResults();
            };

            // 添加显示比对结果视图的函数
            function showComparisonView() {
                // 显示原始数据预览区域和比对结果区域
                const previewSection = document.querySelector('.flex.flex-col.lg\\:flex-row.gap-6.mb-8');
                const comparisonSection = document.querySelector('.bg-gray-50.p-4.rounded-lg.shadow-sm.overflow-x-auto.border.border-gray-200');
                
                if (previewSection) {
                    previewSection.style.display = 'flex';
                }
                if (comparisonSection) {
                    comparisonSection.style.display = 'block';
                }

                // 隐藏输出结果展示区域
                const outputSection = document.querySelector('.bg-gray-50.p-4.rounded-lg.shadow-sm.overflow-x-auto.border.border-gray-200:last-child');
                if (outputSection) {
                    outputSection.style.display = 'none';
                }

                // 记录当前视图状态
                window.currentView = 'comparison';
            }


            loadSavedComparisons(); // Load saved comparisons list first

            // Automatically connect to the mock DB on load
            await connectToDatabase();
        });
    </script>
</body>
</html>
